#include "gui/Checkbox.h"

#include "utilities/Rectangle.h"

namespace gui
{
	Checkbox::Checkbox() : imageSet( NULL )
	{
	}

	Checkbox::Checkbox( const gdn::Vector2f& thePos, bool theCurrentState,
					    gdn::Image& theImageSet,
					    const gdn::Rectanglei& theRectUncheckedIdle, const gdn::Rectanglei& theRectUncheckedHover, const gdn::Rectanglei& theRectUncheckedPress,
					    const gdn::Rectanglei& theRectCheckedIdle, const gdn::Rectanglei& theRectCheckedHover, const gdn::Rectanglei& theRectCheckedPress )
	   : pos( thePos ), mousePos(),
	     imageSet( &theImageSet ),
	     rectUncheckedIdle( theRectUncheckedIdle ), rectUncheckedHover( theRectUncheckedHover ), rectUncheckedPress( theRectUncheckedPress ),
	     rectCheckedIdle( theRectCheckedIdle ), rectCheckedHover( theRectCheckedHover ), rectCheckedPress( theRectCheckedPress ),
		 activeRect( NULL ),
		 hold( false ),
		 currentState( theCurrentState )
	{
		checkboxSprite.SetImage( *imageSet );
		checkboxSprite.SetPosition( pos );

		switch ( currentState )
		{
			case GUI_CHECKBOX_CHECKED:
				activeRect = &rectCheckedHover;
				break;

			case GUI_CHECKBOX_UNCHECKED:
				activeRect = &rectUncheckedHover;
				break;
		}

		checkboxSprite.SetSubRectangle( *activeRect );
	}

	int Checkbox::Process( const gdn::Event& event )
	{
		int ret = GUI_CHECKBOX_IDLE;

		gdn::Vector2< unsigned int > imageSetSize = imageSet->GetSize();

		if ( event.type == gdn::Event::MouseMoved )
		{
			mousePos.x = event.x;
			mousePos.y = event.y;

			if ( util::RectangleContainsPoint< float >( gdn::Rectanglef( pos.x, pos.y, imageSetSize.x / 6, imageSetSize.y ), mousePos ) )
			{
				if ( activeRect != &rectUncheckedPress and activeRect != &rectCheckedPress )
				{
					if ( activeRect == &rectUncheckedHover or activeRect == &rectCheckedHover )
					{
						ret = GUI_CHECKBOX_HOVER;
					}
					else if ( activeRect == &rectUncheckedIdle or activeRect == &rectCheckedIdle )
					{
						ret = GUI_CHECKBOX_ENTER;
					}

					switch ( currentState )
					{
						case GUI_CHECKBOX_CHECKED:
							activeRect = &rectCheckedHover;
							break;

						case GUI_CHECKBOX_UNCHECKED:
							activeRect = &rectUncheckedHover;
							break;
					}
					checkboxSprite.SetSubRectangle( *activeRect );
				}
			}
			else
			{
				if ( activeRect == &rectUncheckedHover and activeRect == &rectCheckedHover )
				{
					ret = GUI_CHECKBOX_EXIT;
				}
				else
				{
					ret = GUI_CHECKBOX_IDLE;
				}

				switch ( currentState )
				{
					case GUI_CHECKBOX_CHECKED:
						activeRect = &rectCheckedIdle;
						break;

					case GUI_CHECKBOX_UNCHECKED:
						activeRect = &rectUncheckedIdle;
						break;
				}
				checkboxSprite.SetSubRectangle( *activeRect );
			}
		}
		else if ( event.type == gdn::Event::MouseButtonPressed and event.mouseButton == gdn::Mouse::Left )
		{
			if ( util::RectangleContainsPoint< float >( gdn::Rectanglef( pos.x, pos.y, imageSetSize.x / 6, imageSetSize.y ), mousePos ) )
			{
				if ( hold != true )
				{
					ret = GUI_CHECKBOX_HOLD;
				}
				else
				{
					ret = GUI_CHECKBOX_PRESS;
				}

				switch ( currentState )
				{
					case GUI_CHECKBOX_CHECKED:
						activeRect = &rectCheckedPress;
						break;

					case GUI_CHECKBOX_UNCHECKED:
						activeRect = &rectUncheckedPress;
						break;
				}
				checkboxSprite.SetSubRectangle( *activeRect );
				hold = true;
			}
		}
		else if ( event.type == gdn::Event::MouseButtonReleased and event.mouseButton == gdn::Mouse::Left )
		{
			if ( util::RectangleContainsPoint< float >( gdn::Rectanglef( pos.x, pos.y, imageSetSize.x / 6, imageSetSize.y ), mousePos ) )
			{
				ret = GUI_CHECKBOX_RELEASE;

				Toggle();
				switch ( currentState )
				{
					case GUI_CHECKBOX_CHECKED:
						activeRect = &rectCheckedHover;
						ret = GUI_CHECKBOX_CHECKED;
						break;

					case GUI_CHECKBOX_UNCHECKED:
						activeRect = &rectUncheckedHover;
						ret = GUI_CHECKBOX_UNCHECKED;
						break;
				}

				checkboxSprite.SetSubRectangle( *activeRect );

				hold = false;
			}
		}

		return currentState;
	}

	void Checkbox::Draw( gdn::Window& window )
	{
		window.Draw( checkboxSprite );
	}

	void Checkbox::Draw( gdn::RenderImage& renderImage )
	{
		renderImage.Draw( checkboxSprite );
	}

	bool Checkbox::IsChecked() const
	{
		return currentState;
	}

	void Checkbox::Toggle()
	{
		if ( currentState == GUI_CHECKBOX_UNCHECKED )
		{
			currentState = GUI_CHECKBOX_CHECKED;
		}
		else if ( currentState == GUI_CHECKBOX_CHECKED )
		{
			currentState = GUI_CHECKBOX_UNCHECKED;
		}
	}
}
